package common

import (
	"encoding/json"
	"errors"
	"sync"
	"time"

	"github.com/sirupsen/logrus"
)

// 单体（进程内）消息分发器

var (
	ErrNoHandler       = errors.New("no handlers found for message")
	ErrInvalidService  = errors.New("service type and ID must not be empty")
	ErrHandlerExists   = errors.New("handler already registered for this service")
	ErrHandlerNotFound = errors.New("handler not found for this service")
)

type MsgHandlerList []IMsgHandler

type MonoMsgDispatcher struct {
	unicastHandlers   map[ServiceInfo]IMsgHandler
	multicastHandlers map[string]MsgHandlerList // key: serviceType, value: handler list
	handlersMtx       sync.RWMutex              // 使用互斥锁保护 handlers 的并发访问
	syncWaiters       map[string]*SyncWaiter
	syncWaitersMtx    sync.Mutex
	timeout           time.Duration // 超时时间，用于同步等待
}

type SyncWaiter struct {
	ch     chan SyncRes
	once   sync.Once
	resCmd string // 用于标识同步响应的类型
}

type SyncRes struct {
	msg    Message
	from   ServiceInfo
	connId string
	err    error
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func NewMonoMsgDispatcher() IMsgDispatcher {
	return &MonoMsgDispatcher{
		unicastHandlers:   make(map[ServiceInfo]IMsgHandler),
		multicastHandlers: make(map[string]MsgHandlerList),
		syncWaiters:       make(map[string]*SyncWaiter),
		timeout:           5 * time.Second, // 默认超时时间为 5 秒
	}
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (d *MonoMsgDispatcher) Register(service ServiceInfo, handler IMsgHandler) error {
	Logger(MODULE_COMMON).WithFields(logrus.Fields{
		"serviceType": service.ServiceType,
		"serviceId":   service.ServiceId,
	}).Info("registering service handler")

	if service.ServiceType == "" || service.ServiceId == "" {
		return ErrInvalidService
	}

	if handler == nil {
		return errors.New("handler must not be nil")
	}

	d.handlersMtx.Lock()
	defer d.handlersMtx.Unlock()

	// Check if the service is already registered
	if _, exists := d.unicastHandlers[service]; exists {
		return ErrHandlerExists
	} else {
		d.unicastHandlers[service] = handler
	}

	// Register the handler for broadcast messages
	if _, exists := d.multicastHandlers[service.ServiceType]; !exists {
		d.multicastHandlers[service.ServiceType] = make(MsgHandlerList, 0)
	}
	d.multicastHandlers[service.ServiceType] = append(d.multicastHandlers[service.ServiceType], handler)

	return nil
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (d *MonoMsgDispatcher) Unregister(service ServiceInfo) error {
	Logger(MODULE_COMMON).WithFields(logrus.Fields{
		"serviceType": service.ServiceType,
		"serviceId":   service.ServiceId,
	}).Info("unregistering service handler")

	d.handlersMtx.Lock()
	defer d.handlersMtx.Unlock()

	// Check if the service is registered
	if _, exists := d.unicastHandlers[service]; !exists {
		return ErrHandlerNotFound
	}

	// Remove the handler from the broadcast handlers
	if handlers, exists := d.multicastHandlers[service.ServiceType]; exists {
		for i, handler := range handlers {
			if handler == d.unicastHandlers[service] {
				// Remove the handler from the slice
				d.multicastHandlers[service.ServiceType] = append(handlers[:i], handlers[i+1:]...)
				break
			}
		}
		if len(d.multicastHandlers[service.ServiceType]) == 0 {
			// If no handlers left for this service type, remove the entry
			delete(d.multicastHandlers, service.ServiceType)
		}
	} else {
		return ErrHandlerNotFound
	}

	// Remove the unicast handler
	delete(d.unicastHandlers, service)

	return nil
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (d *MonoMsgDispatcher) Dispatch(msg Message, from ServiceInfo, to ServiceInfo,
	connId string) error {
	Logger(MODULE_COMMON, msg.Rid).WithFields(logrus.Fields{
		"msg":    ToJson(msg),
		"from":   from,
		"to":     to,
		"connId": connId,
	}).Debug("dispatching message")

	var handlers MsgHandlerList
	if to.ServiceId != "" { // 如果目标服务 ID 不为空，则查找单播处理器
		d.handlersMtx.RLock()
		handler := d.unicastHandlers[to]
		d.handlersMtx.RUnlock()
		if handler == nil {
			return errors.New("no handler found for unicast")
		}
		handlers = []IMsgHandler{handler}
	} else { // 如果目标服务 ID 为空，则查找广播处理器
		var exists bool
		d.handlersMtx.RLock()
		handlers, exists = d.multicastHandlers[to.ServiceType]
		d.handlersMtx.RUnlock()
		if !exists || len(handlers) == 0 {
			return errors.New("no broadcast handlers found for broadcast")
		}
	}

	// 如果没有找到处理器，返回错误
	if len(handlers) == 0 {
		return ErrNoHandler
	}

	// --- 模拟处理消息的过程 ---

	// 1）先将消息转换为 JSON 字符串
	msgJson, err := json.Marshal(msg)
	if err != nil {
		Logger(MODULE_COMMON, msg.Rid).WithError(err).Error("failed to marshal message")
		return err
	}

	// 2）然后将消息再转换回 Message 结构体
	var msgData Message
	if err := json.Unmarshal(msgJson, &msgData); err != nil {
		Logger(MODULE_COMMON, msg.Rid).WithError(err).Error("failed to unmarshal message")
		return err
	}

	// ---- 同步等待处理优先 ----
	if msgData.Rid != "" {
		d.syncWaitersMtx.Lock()
		waiter := d.syncWaiters[msgData.Rid]
		d.syncWaitersMtx.Unlock()
		if waiter != nil && waiter.resCmd == msgData.Cmd {
			waiter.once.Do(func() {
				waiter.ch <- SyncRes{
					msg:    msgData,
					from:   from,
					connId: connId,
					err:    nil,
				}
			})
			return nil // 命中同步，直接返回，不再处理异步
		}
	}

	// ---- 异步处理 ----
	for _, handler := range handlers {
		if handler == nil {
			Logger(MODULE_COMMON, msg.Rid).Error("handler is nil, skipping")
			continue
		}

		// 调用处理函数
		if err := handler.HandleMsg(msgData, from, connId); err != nil {
			Logger(MODULE_COMMON, msg.Rid).WithError(err).Error("failed to handle message")
			return err
		}
	}

	return nil
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (d *MonoMsgDispatcher) DispatchSync(
	msg Message,
	from ServiceInfo,
	to ServiceInfo,
	connId string,
	resCmd string,
) (res *Message, err error) {
	Logger(MODULE_COMMON, msg.Rid).WithFields(logrus.Fields{
		"msg":    ToJson(msg),
		"from":   from,
		"to":     to,
		"connId": connId,
	}).Debug("dispatching sync message")

	if msg.Rid == "" {
		return nil, errors.New("rid must not be empty for sync dispatch")
	}

	waiter := &SyncWaiter{ch: make(chan SyncRes, 1), resCmd: resCmd}
	d.syncWaitersMtx.Lock()
	d.syncWaiters[msg.Rid] = waiter
	d.syncWaitersMtx.Unlock()
	defer func() {
		d.syncWaitersMtx.Lock()
		delete(d.syncWaiters, msg.Rid)
		d.syncWaitersMtx.Unlock()
	}()

	if err := d.Dispatch(msg, from, to, connId); err != nil {
		return nil, err
	}

	select {
	case r := <-waiter.ch:
		return &r.msg, r.err
	case <-time.After(d.timeout):
		return nil, errors.New("dispatch sync timeout")
	}
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (d *MonoMsgDispatcher) DispatchWait(
	msg Message,
	from ServiceInfo,
	to ServiceInfo,
	connId string,
	resCmd string,
) error {
	Logger(MODULE_COMMON, msg.Rid).WithFields(logrus.Fields{
		"msg":    ToJson(msg),
		"from":   from,
		"to":     to,
		"connId": connId,
		"resCmd": resCmd,
	}).Debug("dispatching async wait message")

	if msg.Rid == "" {
		return errors.New("rid must not be empty for wait dispatch")
	}

	if resCmd == "" {
		return errors.New("resCmd must not be empty for wait dispatch")
	}

	// 创建一个同步等待器
	waiter := &SyncWaiter{ch: make(chan SyncRes, 1), resCmd: resCmd}
	d.syncWaitersMtx.Lock()
	d.syncWaiters[msg.Rid] = waiter
	d.syncWaitersMtx.Unlock()

	// 启动超时定时器
	go func(rid string, to ServiceInfo, connId string) {
		select {
		case <-time.After(d.timeout):
			// 超时，构造响应消息并分发给 handler
			d.handlersMtx.RLock()
			handler := d.unicastHandlers[to]
			d.handlersMtx.RUnlock()
			if handler != nil {
				handler.HandleMsg(
					Message{
						Cmd: resCmd,
						Rid: rid,
						Data: ResMsgData{
							Code: RES_TIMEOUT_CMD,
							Msg:  "timeout",
						},
					},
					ServiceInfo{ServiceType: MODULE_COMMON},
					"undefine",
				)
			}
		}
		// 清理 waiter
		d.syncWaitersMtx.Lock()
		delete(d.syncWaiters, rid)
		d.syncWaitersMtx.Unlock()
	}(msg.Rid, to, connId)

	// 发起消息分发
	return d.Dispatch(msg, from, to, connId)
}
